package com.appbee.cm.client.regionunit.presenter;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import javax.inject.Inject;
import javax.inject.Provider;

import com.appbee.cm.shared.data.ActivityEntryProxy;
import com.appbee.cm.shared.data.ActivityEntryRequest;
import com.appbee.cm.shared.data.NavItemProxy;
import com.appbee.cm.shared.dataservice.DataRequestFactory;
import com.appbee.core.client.modular.IModul;
import com.appbee.core.client.modular.IModulRegistry;
import com.appbee.core.client.modular.SettingsView;
import com.appbee.core.client.place.HasPlace;
import com.appbee.core.client.place.INamePlace;
import com.appbee.core.client.ui.IConfirmView;
import com.appbee.user.client.AccessControl;
import com.google.gwt.activity.shared.AbstractActivity;
import com.google.gwt.activity.shared.Activity;
import com.google.gwt.core.client.GWT;
import com.google.gwt.event.shared.EventBus;
import com.google.gwt.place.shared.Place;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.AcceptsOneWidget;
import com.google.gwt.user.client.ui.IsWidget;
import com.google.web.bindery.requestfactory.shared.Receiver;

public class RegionActivity extends AbstractActivity
{

	private final RegionViewProvider viewProvider;
	private final Provider<EditView> editViewProvider;
	private final ActivityEntryControl activityEntryControl;
	private final IModulRegistry modulRegistry;
	private final DataRequestFactory dataRequestFactory;

	private String regionId;
	private Place place = null;
	private NavItemProxy currentNavItem = null;

	private final List<ActivityWrap> activities = new ArrayList<ActivityWrap>();
	private final List<ModulWrap> moduls = new ArrayList<ModulWrap>();
	private final Provider<AddModulView> addModulViewProvider;
	private AcceptsOneWidget panel;
	private EventBus eventBus;
	private final AccessControl accessControl;
	private final IConfirmView confirmView;
	private final StyleRegistry styleRegistry;

	public interface View extends IsWidget
	{
		void setPresenter(RegionActivity presenter);

		List<ModulView> createActivityPanels(int n);

	}

	public interface ModulView extends AcceptsOneWidget
	{
		void setPresenter(ModulPresenter presenter);

		void setStyle(String style);
	}

	public interface AddModulView extends IsWidget
	{
		void setPresenter(RegionActivity presenter);

	}

	public interface EditView
	{
		void show(Object source);

		void hide();

		IModul getSelectedModul();

		void setSelectedModul(IModul selectedModul);

		void setPresenter(ModulPresenter presenter);

		void setSettingsView(SettingsView settingsView);

		void setStyles(List<StyleInfo> styles);

		void setSelectedStyle(StyleInfo byId);

		StyleInfo getSelectedStyle();

		int getNumber();

		void setNumber(int number);

	}

	@Inject
	public RegionActivity(	RegionViewProvider viewProvider,
							AccessControl accessControl,
							Provider<EditView> editViewProvider,
							Provider<AddModulView> addModulViewProvider,
							IConfirmView confirmView,
							ActivityEntryControl activityEntryControl,
							IModulRegistry modulRegistry,
							StyleRegistry styleRegistry,
							DataRequestFactory dataRequestFactory)
	{
		this.viewProvider = viewProvider;
		this.accessControl = accessControl;
		this.editViewProvider = editViewProvider;
		this.addModulViewProvider = addModulViewProvider;
		this.confirmView = confirmView;
		this.activityEntryControl = activityEntryControl;
		this.modulRegistry = modulRegistry;
		this.styleRegistry = styleRegistry;
		this.dataRequestFactory = dataRequestFactory;

	}

	public void setRegionId(String regionId)
	{
		this.regionId = regionId;
	}

	public void setCurrentNavItem(NavItemProxy currentNavItem)
	{
		this.currentNavItem = currentNavItem;
	}

	public void setPlace(Place place)
	{
		this.place = place;
	}

	@Override
	public String mayStop()
	{
		for (ActivityWrap activityWrap : activities)
		{
			String msg = activityWrap.activity.mayStop();
			if (msg != null)
				return msg;
		}
		return null;
	}

	@Override
	public void onCancel()
	{
		for (ActivityWrap activityWrap : activities)
		{
			activityWrap.activity.onCancel();
		}
	}

	@Override
	public void onStop()
	{
		for (ActivityWrap activityWrap : activities)
		{
			activityWrap.activity.onStop();
		}
	}

	@Override
	public void start(final AcceptsOneWidget panel, final EventBus eventBus)
	{
		View view = viewProvider.getView(regionId);
		GWT.log("Region: " + regionId + ", view: " + view.hashCode());
		view.setPresenter(this);
		this.panel = panel;
		this.eventBus = eventBus;

		// Find activities
		findModuls();

		if (moduls.isEmpty() && accessControl.isMemberOrAdmin())
		{
			// Set add button
			AddModulView addModulView = addModulViewProvider.get();
			addModulView.setPresenter(this);
			panel.setWidget(addModulView);
		}
		else
		{
			// Start sub activities
			List<ModulView> activityPanels = view
.createActivityPanels(moduls
					.size());
			for (int i = 0; i < activityPanels.size(); i++)
			{
				final ModulView subPanel = activityPanels.get(i);
				GWT.log("Sumpanel: " + subPanel.hashCode());

				final ModulWrap modul = moduls.get(i);

				modul.modul.getActivity((INamePlace) place,
										new AsyncCallback<Activity>()
										{

											@Override
											public void onSuccess(Activity activity)
											{
												if (activity == null)
													return;
												// Set place
												if (activity instanceof HasPlace)
												{
													HasPlace hasPlace = (HasPlace) activity;
													hasPlace.setPlace(place);
												}

												// Set activity entry
												if (activity instanceof HasActivityEntry)
												{

													((HasActivityEntry) activity)
															.setActivityEntry(modul.activityEntry);
												}

												ActivityWrap activityWrap = new ActivityWrap(
														modul.activityEntry,
														activity);
												activities.add(activityWrap);

												StyleInfo styleInfo = styleRegistry
														.getById(modul.activityEntry
																.getStyleId());
												subPanel.setStyle(styleInfo == null ? ""
														: styleInfo.getStyle());
												subPanel.setPresenter(new ModulPresenter(
														activityWrap));
												activity.start(	subPanel,
																eventBus);

											}

											@Override
											public void onFailure(Throwable caught)
											{
											}
										});

			}

			panel.setWidget(view);
		}
	}

	private void findModuls()
	{
		moduls.clear();
		Long navId = currentNavItem == null ? null : currentNavItem.getId();
		List<ActivityEntryProxy> activityList = activityEntryControl
				.getByNavAndRegionId(navId, regionId);

		// Sort
		Collections.sort(activityList, new Comparator<ActivityEntryProxy>()
		{

			@Override
			public int compare(ActivityEntryProxy a1, ActivityEntryProxy a2)
			{
				int n1 = a1.getNumber();
				int n2 = a2.getNumber();
				if (n1 == n2)
					return 0;
				else if (n1 < n2)
					return -1;
				return 1;
			}

		});

		for (ActivityEntryProxy activityEntry : activityList)
		{
			IModul modul = modulRegistry.getById(activityEntry
					.getActivityModulId());
			if (modul == null)
				continue;

			modul.setCurrentNavItem(currentNavItem);
			moduls.add(new ModulWrap(activityEntry, modul));
		}
	}

	public void doAdd(Object source)
	{
		EditView editView = editViewProvider.get();
		editView.setSettingsView(null);
		editView.setStyles(styleRegistry.getStyles());
		editView.setSelectedModul(null);
		editView.setSelectedStyle(null);
		ModulPresenter presenter = new ModulPresenter(editView);
		editView.setPresenter(presenter);
		editView.show(source);
	}

	private class ActivityWrap
	{
		final ActivityEntryProxy activityEntry;
		final Activity activity;

		public ActivityWrap(ActivityEntryProxy activityEntry, Activity activity)
		{
			this.activityEntry = activityEntry;
			this.activity = activity;
		}

	}

	private class ModulWrap
	{
		final ActivityEntryProxy activityEntry;
		final IModul modul;

		public ModulWrap(ActivityEntryProxy activityEntry, IModul modul)
		{
			this.activityEntry = activityEntry;
			this.modul = modul;

		}

	}

	public class ModulPresenter
	{
		private final ActivityWrap activityWrap;
		private EditView editView;
		private SettingsView settingsView;

		public ModulPresenter(ActivityWrap activityWrap)
		{
			this.activityWrap = activityWrap;
		}

		public ModulPresenter(EditView editView)
		{
			this.editView = editView;
			activityWrap = null;
		}

		public void doDelete()
		{
			if (!confirmView
					.confirm("Are you sure you want to delete this unit?"))
				return;

			dataRequestFactory.getActivityEntryRequest()
					.delete(activityWrap.activityEntry)
					.fire(new Receiver<Void>()
					{
						@Override
						public void onSuccess(Void response)
						{
							activityEntryControl.remove(activityWrap.activityEntry);
							onStop();
							start(panel, eventBus);
						}
					});
		}

		public void doEdit(final Object source)
		{
			if (editView == null)
			{
				editView = editViewProvider.get();
				editView.setPresenter(this);
				editView.setStyles(styleRegistry.getStyles());
			}
			final IModul modul = modulRegistry
					.getById(activityWrap.activityEntry
					.getActivityModulId());
			modul.getSettingsView(new AsyncCallback<SettingsView>()
			{

				@Override
				public void onSuccess(SettingsView result)
				{
					settingsView = result;
					if (result != null)
					{
						result.setSettingsString(activityWrap.activityEntry
								.getSettings());

					}
					editView.setSelectedModul(modul);
					editView.setSelectedStyle(styleRegistry
							.getById(activityWrap.activityEntry.getStyleId()));
					editView.setNumber(activityWrap.activityEntry.getNumber());
					editView.setSettingsView(result);

					editView.show(source);

				}

				@Override
				public void onFailure(Throwable caught)
				{
				}
			});
		}

		public void doSave()
		{
			final ActivityEntryRequest request = dataRequestFactory
					.getActivityEntryRequest();
			ActivityEntryProxy activityEntryForEdit = null;
			if (activityWrap == null)
			{
				activityEntryForEdit = request.create(ActivityEntryProxy.class);
			}
			else
			{
				activityEntryForEdit = activityWrap.activityEntry;
			}
			final ActivityEntryProxy activityEntry = request
					.edit(activityEntryForEdit);
			IModul selectedModul = editView.getSelectedModul();
			activityEntry.setActivityModulId(selectedModul == null ? ""
					: selectedModul.getId());
			StyleInfo selectedStyle = editView.getSelectedStyle();
			activityEntry.setStyleId(selectedStyle == null ? "" : selectedStyle
					.getId());
			activityEntry.setNumber(editView.getNumber());
			activityEntry.setSettings(settingsView == null ? "" : settingsView
					.toSettingsString());
			activityEntry.setRegionId(regionId);
			activityEntry.setNavItemId(currentNavItem == null ? null
					: currentNavItem.getId());
			request.save(activityEntry).fire(new Receiver<ActivityEntryProxy>()
			{

				@Override
				public void onSuccess(ActivityEntryProxy response)
				{
					activityEntryControl.update(response);
					editView.hide();
					onStop();
					start(panel, eventBus);
				}

			});

		}

		public void doModulSelected(IModul value)
		{
			if (value == null)
				editView.setSettingsView(null);
			else
			{
				value.getSettingsView(new AsyncCallback<SettingsView>()
				{

					@Override
					public void onSuccess(SettingsView result)
					{
						settingsView = result;
						editView.setSettingsView(result);
					}

					@Override
					public void onFailure(Throwable caught)
					{
					}
				});
			}
		}

	}


}
